#include "stdafx.h"
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/execution_monitor.hpp>
#include "bmock.hpp"
#include "bmock_control_tools_mock.hpp"
#include <string>

static void f() {
	STATIC_MOCK_VOID(0,());
}
static void g() {
	STATIC_MOCK_VOID(0,());
}
static int k() {
	STATIC_MOCK(0,());	
}

static void h()
{
	g();
}

static void h1() {
}
static int h2() {
	return 0;
}



struct repetition_tester{
	int result;
};

BOOST_AUTO_TEST_CASE(testFunctionCall_ReplayWithoutExpect) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+6);

	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		BOOST_CHECK_NO_THROW(__BMOCK_REPLAY_C(c1));
		BOOST_CHECK_NO_THROW(__BMOCK_VERIFY_C(c1));
	}
 	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_DuplicateReplay) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+8);

	__BMOCK_EXPECT_THROW_C(c,new bmock::location(loc),t->error(bmock::message(bmock::INVALID_REPLAY),loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_THROW(__BMOCK_REPLAY_C(c1),bmock::location);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_MisplacedVerify) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+7);

	__BMOCK_EXPECT_THROW_C(c,new bmock::location(loc),t->error(bmock::message(bmock::INVALID_VERIFY),loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
		BOOST_CHECK_THROW(__BMOCK_VERIFY_C(c1),bmock::location);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_NotReceived) {
	const char *msg = "Function call 'f' has not been received (expected: 1, actual: 0)";
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+6);

	__BMOCK_EXPECT_THROW_C(c,new bmock::location(loc),t->error(msg,loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_THROW(__BMOCK_VERIFY_C(c1),bmock::location);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_Received) {
	__BMOCK_CONTROL(c);
	__BMOCK_EXPECT_C(c,f());
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(f());
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_Wrong) {
	const std::string msg = "BMOCK_EXPECT_STR(g,\"test_function_call.cpp\",12,0,());";
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+6);

	__BMOCK_EXPECT_THROW_C(c,new boost::execution_aborted(),t->error(msg,loc,true));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_THROW(g(),boost::execution_aborted);
		__BMOCK_VERIFY_C(c1);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_MissingReplay) {
	const std::string msg = "BMOCK_EXPECT_STR(f,\"test_function_call.cpp\",9,0,());";
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+6);

	__BMOCK_EXPECT_THROW_C(c,new bmock::location(loc),t->error(msg+"(m.b. BMOCK_REPLAY is missing)",loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		BOOST_CHECK_THROW(f(),bmock::location);
	}
	__BMOCK_VERIFY_C(c);
}


BOOST_AUTO_TEST_CASE(testFunctionCall_Unexpected) {
	const std::string msg = "BMOCK_EXPECT_STR(f,\"test_function_call.cpp\",9,0,());";
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+7);

	__BMOCK_EXPECT_THROW_C(c,new bmock::location(loc),t->error(msg,loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_NO_THROW(f());
		BOOST_CHECK_THROW(f(),bmock::location);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_ReplayAfterVerify) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+10);

	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_NO_THROW(f());
		__BMOCK_VERIFY_C(c1);
		BOOST_CHECK_NO_THROW(__BMOCK_REPLAY_C(c1));
		__BMOCK_VERIFY_C(c1);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_ReplayAfterCheck) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+9);

	__BMOCK_EXPECT_THROW_C(c,new bmock::location(loc),t->error(bmock::message(bmock::INVALID_REPLAY),loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_NO_THROW(f());
		BOOST_CHECK_THROW(__BMOCK_REPLAY_C(c1),bmock::location);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_DuplicateVerify) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+10);

	__BMOCK_EXPECT_THROW_C(c,new bmock::location(loc),t->error(bmock::message(bmock::INVALID_VERIFY),loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_NO_THROW(f());
		__BMOCK_VERIFY_C(c1);
		BOOST_CHECK_THROW(__BMOCK_VERIFY_C(c1),bmock::location);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_ExpectAfterVerify) {
	__BMOCK_CONTROL(c);

	__BMOCK_EXPECT_C(c,f());
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(f());
	__BMOCK_VERIFY_C(c);
	__BMOCK_EXPECT_C(c,f());
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_NO_THROW(f());
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_CheckAfterVerify) {
	const std::string msg = "BMOCK_EXPECT_STR(f,\"test_function_call.cpp\",9,0,());";
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+10);

	__BMOCK_EXPECT_THROW_C(c,new bmock::location(loc),t->error(msg+"(m.b. BMOCK_REPLAY is missing)",loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_NO_THROW(f());
		__BMOCK_VERIFY_C(c1);
		BOOST_CHECK_THROW(f(),bmock::location);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_UnexpectedDestructor_Verify) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));

	__BMOCK_EXPECT_C(c,t->error(bmock::message(bmock::INVALID_TERMINATE),bmock::location(__FILE__,__LINE__+6)));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_NO_THROW(f());
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_UnexpectedDestructor_Check) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));

	__BMOCK_EXPECT_C(c,t->error(bmock::message(bmock::INVALID_TERMINATE),bmock::location(__FILE__,__LINE__+7)));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
		__BMOCK_REPLAY_C(c1);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_UnexpectedDestructor_Replay) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));

	__BMOCK_EXPECT_C(c,t->error(bmock::message(bmock::INVALID_TERMINATE),bmock::location(__FILE__,__LINE__+5)));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_ExpectForNonMock_void) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+6);

	__BMOCK_EXPECT_C(c,t->error(bmock::message(bmock::EXPECT_FOR_NON_MOCK),loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,h1());
		__BMOCK_REPLAY_C(c1);
		__BMOCK_VERIFY_C(c1);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_ExpectForNonMock_int) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+6);

	__BMOCK_EXPECT_C(c,t->error(bmock::message(bmock::EXPECT_FOR_NON_MOCK),loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_RETURN_C(c1,1,h2());
		__BMOCK_REPLAY_C(c1);
		__BMOCK_VERIFY_C(c1);
	}
	__BMOCK_VERIFY_C(c);
}

BOOST_AUTO_TEST_CASE(testFunctionCall_ExpectForNonMock_exception) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+6);

	__BMOCK_EXPECT_C(c,t->error(bmock::message(bmock::EXPECT_FOR_NON_MOCK),loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_THROW_C(c1,new bmock::location(),h2());
		__BMOCK_REPLAY_C(c1);
		__BMOCK_VERIFY_C(c1);
	}
	__BMOCK_VERIFY_C(c);
}
BOOST_AUTO_TEST_CASE(test_mock_call_without_expect_before_replay) {
	const std::string msg = "BMOCK_EXPECT_STR(g,\"test_function_call.cpp\",12,0,());";
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+6);

	__BMOCK_EXPECT_THROW_C(c,new bmock::location(loc),t->error(msg+"(m.b. BMOCK_REPLAY is missing)",loc));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_C(c1,f());
		BOOST_CHECK_THROW(h(),bmock::location);
		__BMOCK_REPLAY_C(c1);
		BOOST_CHECK_NO_THROW(f());
		__BMOCK_VERIFY_C(c1);
	}
	__BMOCK_VERIFY_C(c);
}

BMOCK_TEST(repetition_tester,testVoidFunctionCall_Repetition) {
	BMOCK_EXPECT(f());
	BMOCK_REPEAT(5);
	BMOCK_REPLAY;
	for(int i=0;i<5;i++)
		BOOST_CHECK_NO_THROW(f());
	BMOCK_VERIFY;
}

BMOCK_TEST(repetition_tester,testFunctionCall_Repetition) {
	BMOCK_EXPECT_RETURN(result,k());
	BMOCK_REPEAT(5);
	BMOCK_REPLAY;
	for(int i=0;i<5;i++)
		BOOST_CHECK_NO_THROW(k());
	BMOCK_VERIFY;
}

BMOCK_TEST(repetition_tester, testFunctionCall_Repetition_range_same_as_max) {
	BMOCK_EXPECT_RETURN(result,k());
	BMOCK_REPEAT_RANGE(1,5);
	BMOCK_REPLAY;
	for(int i=0;i<5;i++)
		BOOST_CHECK_NO_THROW(k());
	BMOCK_VERIFY;
}

BMOCK_TEST(repetition_tester, testFunctionCall_Repetition_range_same_as_min) {
	BMOCK_EXPECT_RETURN(result,k());
	BMOCK_REPEAT_RANGE(1,5);
	BMOCK_REPLAY;
	for(int i=0;i<1;i++)
		BOOST_CHECK_NO_THROW(k());
	BMOCK_VERIFY;
}

BMOCK_TEST(repetition_tester, testFunctionCall_Repetition_range_between_max_and_min) {
	BMOCK_EXPECT_RETURN(result,k());
	BMOCK_REPEAT_RANGE(1,5);
	BMOCK_EXPECT(f());
	BMOCK_REPLAY;
	for(int i=0;i<3;i++)
		BOOST_CHECK_NO_THROW(k());
	BOOST_CHECK_NO_THROW(f());
	BMOCK_VERIFY;
}

BMOCK_TEST(repetition_tester, testFunctionCall_Repetition_range_between_max_and_min_infinite_max) {
	BMOCK_EXPECT_RETURN(result,k());
	BMOCK_REPEAT_RANGE(1,BMOCK_INFINITE);
	BMOCK_EXPECT(f());
	BMOCK_REPLAY;
	for(int i=0;i<3;i++)
		BOOST_CHECK_NO_THROW(k());
	BOOST_CHECK_NO_THROW(f());
	BMOCK_VERIFY;
}

BMOCK_TEST(repetition_tester, testFunctionCall_Repetition_range_max_infinite) {
	BMOCK_EXPECT_RETURN(result,k());
	BMOCK_REPEAT_RANGE(3,BMOCK_INFINITE);
	BMOCK_EXPECT(f());
	BMOCK_REPLAY;
	for(int i=0;i < 100;i++)
		BOOST_CHECK_NO_THROW(k());
	BOOST_CHECK_NO_THROW(f());
	BMOCK_VERIFY;
}

BMOCK_TEST(repetition_tester, testFunctionCall_Repetition_range_called_more_than_max) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
	const bmock::location          loc(__FILE__,__LINE__+9);
	const std::string msg = "BMOCK_EXPECT_RETURN_STR(int,k,\"test_function_call.cpp\",15,0,());";

	__BMOCK_EXPECT_THROW_C(c,new boost::execution_aborted(),t->error(msg,loc,true));
	__BMOCK_REPLAY_C(c);
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_RETURN_C(c1, result, k());
		__BMOCK_REPEAT_RANGE_C(c1, 1, 5);
		__BMOCK_REPLAY_C(c1);
		{
			for(int i=0;i<5;i++)
				BOOST_CHECK_NO_THROW(k());
			BOOST_CHECK_THROW(k(),boost::execution_aborted);
		}
	}
	__BMOCK_VERIFY_C(c);
}

BMOCK_TEST(repetition_tester, testFunctionCall_Repetition_range_called_less_than_min) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
#ifndef __clang__
	const bmock::location          loc(__FILE__,__LINE__+18);
#else
	const bmock::location          loc(__FILE__,__LINE__+9);
#endif
	const std::string msg = "Function call 'k' has not been received (expected: 3, actual: 2)";

	__BMOCK_EXPECT_THROW_C(c,new bmock::location(loc),t->error(msg.c_str(),loc));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_THROW( 
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_RETURN_C(c1,result,k());
		__BMOCK_REPEAT_RANGE_C(c1, 3, 5);
		__BMOCK_REPLAY_C(c1);
		for(int i=0;i<2;i++)
			BOOST_CHECK_NO_THROW(k());		
		__BMOCK_VERIFY_C(c1);
	}	
	,bmock::location);
	__BMOCK_VERIFY_C(c);
}

BMOCK_TEST(repetition_tester, testFunctionCall_Repetition_range_called_less_than_min_infinite_max) {
	__BMOCK_CONTROL(c);
	const bmock::control_tools_ptr t(new bmock::control_tools_mock(c));
#ifndef __clang__
	const bmock::location          loc(__FILE__,__LINE__+18);
#else
	const bmock::location          loc(__FILE__,__LINE__+9);
#endif
	const std::string msg = "Function call 'k' has not been received (expected: 3, actual: 1)";

	__BMOCK_EXPECT_THROW_C(c,new bmock::location(loc),t->error(msg.c_str(),loc));
	__BMOCK_REPLAY_C(c);
	BOOST_CHECK_THROW( 
	{
		bmock::test_mode_control c1(bmock::location(__FILE__,__LINE__),t);
		__BMOCK_EXPECT_RETURN_C(c1,result,k());
		__BMOCK_REPEAT_RANGE_C(c1, 3, BMOCK_INFINITE);
		__BMOCK_REPLAY_C(c1);
		for(int i=0;i<1;i++)
			BOOST_CHECK_NO_THROW(k());		
		__BMOCK_VERIFY_C(c1);
	}	
	,bmock::location);
	__BMOCK_VERIFY_C(c);
}
